package com.wst.system.security.jwt;

import com.alibaba.fastjson2.JSONObject;
import com.wst.system.config.Constant;
import com.wst.system.config.cache.SysCache;
import com.wst.system.config.cache.SysCacheServer;
import com.wst.system.config.exception.GlobalExcetion;
import com.wst.system.security.config.AppJWTConfig;
import com.wst.system.security.config.JWTConfig;
import com.wst.system.security.config.ReflushJWTConfig;
import com.wst.system.security.config.UserTypeEnum;
import com.wst.system.security.entity.SelfUserEntity;
import com.wst.system.security.entity.SysUserTokenEntity;
import com.wst.system.server.entity.SysOpenToken;
import com.wst.system.server.service.SysOpenTokenService;
import com.wst.system.server.service.SysUserTokenService;
import com.wst.system.util.CookieUtils;
import com.wst.system.util.ResultUtil;
import com.wst.system.util.SpringContextUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class JWTAuthenticationTokenFilter  extends BasicAuthenticationFilter {

    public JWTAuthenticationTokenFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Cookie[] cookies=request.getCookies();
        // 获取请求头中JWT的Token
        String tokenHeader = request.getHeader(JWTConfig.tokenHeader);
        String appTokenHeader=request.getHeader(AppJWTConfig.tokenHeader);
        String flushTokenHeader=request.getHeader(ReflushJWTConfig.tokenHeader);
        if(tokenHeader!=null){
            //系统 token
            tokenHeader = tokenHeader.replace(JWTConfig.tokenPrefix, "");
            dealToken(request,response,filterChain,tokenHeader);
        }else if(appTokenHeader!=null){
            //app token
            appTokenHeader = appTokenHeader.replace(AppJWTConfig.tokenPrefix, "");
            dealAppToken(request,response,filterChain,appTokenHeader);
        }else if(flushTokenHeader!=null){
            //token 刷新
            flushTokenHeader = flushTokenHeader.replace(ReflushJWTConfig.tokenPrefix, "");
            dealReflushToken(request,response,filterChain,flushTokenHeader);
        }else {
            Cookie cookie= CookieUtils.getCookieByName(cookies,JWTConfig.tokenHeader);
            if(cookie != null){
                String token = cookie.getValue();
                token=token.replace(JWTConfig.tokenPrefix,"");
                dealToken(request,response,filterChain,token);
            }
        }
        filterChain.doFilter(request, response);
        return;
    }

    public void dealToken(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain,String token){
        try {
            log.info("开始解析jwt");
            // 解析JWT
            Claims claims = Jwts.parser()
                    .setSigningKey(JWTConfig.secret)
                    .parseClaimsJws(token)
                    .getBody();
            // 使用签发时间
            Date date=claims.getIssuedAt();
            log.info("jwt签发时间:{}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
            log.info("jwt获取权限:{}",claims.get("authorities",String.class));
            Date current=new Date();
            System.out.println(current.getTime() - date.getTime());
            if((current.getTime() - date.getTime()) > 10000){
                SysUserTokenService service= SpringContextUtils.getBean(SysUserTokenService.class);
                SysUserTokenEntity userToken=service.getSysUserTokenByToken(JWTConfig.tokenPrefix+token,Constant.USER_TOKEN);
                if(userToken!=null){
                    pass(JWTConfig.tokenHeader,JWTConfig.tokenPrefix,token,claims,response);
                }
            }else {
                pass(JWTConfig.tokenHeader,JWTConfig.tokenPrefix,token,claims,response);
            }
        } catch (ExpiredJwtException e){
            log.info("Token过期");
        } catch (Exception e) {
            log.info("Token无效");
        }
    }


    public void dealReflushToken(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain,String token){
        try {
            log.info("开始解析reflush token");
            // 解析JWT
            Claims claims = Jwts.parser()
                    .setSigningKey(ReflushJWTConfig.secret)
                    .parseClaimsJws(token)
                    .getBody();
            // 使用签发时间
            Date date=claims.getIssuedAt();
            log.info("jwt签发时间:{}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
            log.info("jwt获取权限:{}",claims.get("authorities",String.class));
            Date current=new Date();
            System.out.println(current.getTime() - date.getTime());
            if((current.getTime() - date.getTime()) > 10000){
                SysUserTokenService service= SpringContextUtils.getBean(SysUserTokenService.class);
                SysUserTokenEntity userToken=service.getSysUserTokenByToken(ReflushJWTConfig.tokenPrefix+token,Constant.REFLUSH_TOKEN);
                if(userToken!=null){
                    pass(ReflushJWTConfig.tokenHeader,ReflushJWTConfig.tokenPrefix,token,claims,response);
                }
            }else {
                pass(ReflushJWTConfig.tokenHeader,ReflushJWTConfig.tokenPrefix,token,claims,response);
            }
        } catch (ExpiredJwtException e){
            log.info("Token过期");
        } catch (Exception e) {
            log.info("Token无效");
        }
    }


    public void dealAppToken(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain,String token){
        try {
            log.info("开始解析apptoken");
            // 解析JWT
            Claims claims = Jwts.parser()
                    .setSigningKey(AppJWTConfig.secret)
                    .parseClaimsJws(token)
                    .getBody();
            // 使用签发时间
            Date date=claims.getIssuedAt();
            log.info("jwt签发时间:{}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
            log.info("jwt获取权限:{}",claims.get("authorities",String.class));
            Date current=new Date();
            System.out.println(current.getTime() - date.getTime());
            //判断接口地址是否是api接口
            if((current.getTime() - date.getTime()) > 10000){
                SysOpenTokenService service=SpringContextUtils.getBean(SysOpenTokenService.class);
                SysOpenToken apptoken=service.getSysOpenTokenByToken(AppJWTConfig.tokenPrefix+token);
                if(apptoken!=null){
                    pass(AppJWTConfig.tokenHeader,AppJWTConfig.tokenPrefix,token,claims,response);
                }
            }else {
                pass(AppJWTConfig.tokenHeader,AppJWTConfig.tokenPrefix,token,claims,response);
            }
        }catch (ExpiredJwtException e){
            log.info("app token已过期");
            JSONObject obj=new JSONObject();
            obj.put("code",1);
            obj.put("msg","app token已过期");
            ResultUtil.responseJson(response,obj);
        }catch (Exception e){
            log.info("app token无效");
            JSONObject obj=new JSONObject();
            obj.put("code",1);
            obj.put("msg","app token无效");
            ResultUtil.responseJson(response,obj);
        }
    }



    public void pass(String tokenHeader,String tokenPrefix,String token,Claims claims,HttpServletResponse response){
        String userId=claims.getId();
        String username = claims.getSubject();
        if(!StringUtils.isEmpty(username)&&!StringUtils.isEmpty(userId)) {
            // 获取角色
            List<GrantedAuthority> authorities = new ArrayList<>();
            String authority = claims.get("authorities").toString();
            if(!StringUtils.isEmpty(authority)){
                List<Map<String,String>> authorityMap = JSONObject.parseObject(authority, List.class);
                for(Map<String,String> role : authorityMap){
                    if(!StringUtils.isEmpty(role)) {
                        authorities.add(new SimpleGrantedAuthority(role.get("authority")));
                    }
                }
            }
            //组装参数
            SelfUserEntity selfUserEntity = new SelfUserEntity();
            selfUserEntity.setUsername(claims.getSubject());
            selfUserEntity.setUserId(Integer.valueOf(claims.getId()));
            selfUserEntity.setAuthorities(authorities);
            if(tokenHeader.equals(AppJWTConfig.tokenHeader)){
                selfUserEntity.setUserType(UserTypeEnum.APP.getType());
            }else if(tokenHeader.equals(JWTConfig.tokenHeader)){
                selfUserEntity.setUserType(UserTypeEnum.USER.getType());
            }else if(tokenHeader.equals(ReflushJWTConfig.tokenHeader)){
                selfUserEntity.setUserType(UserTypeEnum.FLUSHTOKEN.getType());
            }else {
                selfUserEntity.setUserType(UserTypeEnum.NONE.getType());
            }
            //如果设置此项失败，则将不允许登录
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(selfUserEntity, userId, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
    }
}
